#include "KTimerQueue.h"
#include "KDebug.h"
#include "KGlobal.h"

KTimerQueue::KTimerQueue()
{
    if ((m_queue = CreateTimerQueue())) {
        KDebugLib("KTimerQueue: created");
    } else {
        KDebugLib("CreateTimerQueue() failed: %d", GetLastError());
    }
}

KTimerQueue::~KTimerQueue()
{
    stopAll();
    assert(m_queue == NULL);
}

bool KTimerQueue::stopAll()
{
    if (m_queue) {
        if (DeleteTimerQueueEx(m_queue, INVALID_HANDLE_VALUE)) {
            m_queue = NULL;
            KDebugLib("KTimerQueue: destroyed");
        } else {
            KDebugLib("DeleteTimerQueueEx() failed: %d", GetLastError());
            return false;
        }
    }
    return true;
}

KTimer::KTimer(KTimerQueue *queue) : m_timer(NULL), m_queue(queue)
{
}

KTimer::~KTimer()
{
    bool ok = stop();
    assert(ok);
}

bool KTimer::reset(DWORD dueTime, DWORD period)
{
    if (m_timer) {
        assert(!m_queue || m_queue->isAlive());
        if (ChangeTimerQueueTimer(m_queue ? m_queue->handle() : NULL, m_timer, dueTime, period)) {
            return true;
        } else {
            KDebugLib("ChangeTimerQueueTimer() failed: %d", GetLastError());
            return false;
        }
    }
    return start(dueTime, period);
}

bool KTimer::start(DWORD dueTime, DWORD period)
{
    if (!m_timer) {
        assert(!m_queue || m_queue->isAlive());
        if (CreateTimerQueueTimer(&m_timer, m_queue ? m_queue->handle() : NULL, KTimer::TimerProc,
            static_cast<KTimer *>(this), dueTime, period, 0)) {
            KDebugLib("KTimer: started");
        } else {
            KDebugLib("CreateTimerQueueTimer() failed: %d", GetLastError());
            assert(m_timer == NULL);
            return false;
        }
    }
    return true;
}

bool KTimer::stop()
{
    if (m_timer) {
        HANDLE queue = NULL;
        if (m_queue) {
            if (m_queue->isAlive()) {
                queue = m_queue->handle();
            } else {
                m_timer = NULL;
                KDebugLib("KTimer: stopped by KTimerQueue already");
                return true;
            }
        }
        DWORD lastErr;
        if (DeleteTimerQueueTimer(queue, m_timer, INVALID_HANDLE_VALUE) ||
            (lastErr = GetLastError()) == ERROR_IO_PENDING) {
            m_timer = NULL;
            KDebugLib("KTimer: stopped");
        } else {
            KDebugLib("DeleteTimerQueueTimer() failed: %d", lastErr);
            return false;
        }
    }
    return true;
}

void KTimer::tick()
{
    KDebugMsg("Warning: virtual function KTimer::tick() called");
}

VOID CALLBACK KTimer::TimerProc(PVOID lpTimer, BOOLEAN)
{
    assert(lpTimer != NULL);
    KTimer *lpThis = static_cast<KTimer *>(lpTimer);
    return lpThis->tick();
}